// Filename: memoryUsage.I
// Created by:  drose (25May00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University.  All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license.  You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::track_memory_usage
//       Access: Public, Static
//  Description: Returns true if the user has Configured the variable
//               'track-memory-usage' to true, indicating that this
//               class will be in effect.  If this returns false, the
//               user has indicated not to do any of this.
////////////////////////////////////////////////////////////////////
INLINE bool MemoryUsage::
get_track_memory_usage() {
  return get_global_ptr()->_track_memory_usage;
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::record_pointer
//       Access: Public, Static
//  Description: Indicates that the given pointer has been recently
//               allocated.
////////////////////////////////////////////////////////////////////
INLINE void MemoryUsage::
record_pointer(ReferenceCount *ptr) {
  get_global_ptr()->ns_record_pointer(ptr);
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::update_type
//       Access: Public, Static
//  Description: Associates the indicated type with the given pointer.
//               This should be called by functions (e.g. the
//               constructor) that know more specifically what type of
//               thing we've got; otherwise, the MemoryUsage database
//               will know only that it's a "ReferenceCount".
////////////////////////////////////////////////////////////////////
INLINE void MemoryUsage::
update_type(ReferenceCount *ptr, TypeHandle type) {
  get_global_ptr()->ns_update_type(ptr, type);
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::update_type
//       Access: Public, Static
//  Description: Associates the indicated type with the given pointer.
//               This flavor of update_type() also passes in the
//               pointer as a TypedObject, and useful for objects that
//               are, in fact, TypedObjects.  Once the MemoryUsage
//               database has the pointer as a TypedObject it doesn't
//               need any more help.
////////////////////////////////////////////////////////////////////
INLINE void MemoryUsage::
update_type(ReferenceCount *ptr, TypedObject *typed_ptr) {
  get_global_ptr()->ns_update_type(ptr, typed_ptr);
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::remove_pointer
//       Access: Public, Static
//  Description: Indicates that the given pointer has been recently
//               freed.
////////////////////////////////////////////////////////////////////
INLINE void MemoryUsage::
remove_pointer(ReferenceCount *ptr) {
  get_global_ptr()->ns_remove_pointer(ptr);
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::is_tracking
//       Access: Public, Static
//  Description: Returns true if the MemoryUsage object is currently
//               tracking memory (e.g. track-memory-usage is
//               configured #t).
////////////////////////////////////////////////////////////////////
INLINE bool MemoryUsage::
is_tracking() {
  return get_global_ptr()->_track_memory_usage;
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::is_counting
//       Access: Public, Static
//  Description: Returns true if the MemoryUsage object is currently
//               at least counting memory (e.g. this is a Windows
//               debug build), even if it's not fully tracking it.
////////////////////////////////////////////////////////////////////
INLINE bool MemoryUsage::
is_counting() {
  return get_global_ptr()->_count_memory_usage;
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::get_current_cpp_size
//       Access: Public, Static
//  Description: Returns the total number of bytes of allocated memory
//               consumed by C++ objects, not including the memory
//               previously frozen.
////////////////////////////////////////////////////////////////////
INLINE size_t MemoryUsage::
get_current_cpp_size() {
  return get_global_ptr()->_current_cpp_size;
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::get_total_cpp_size
//       Access: Public, Static
//  Description: Returns the total number of bytes of allocated memory
//               consumed by C++ objects, including the memory
//               previously frozen.
////////////////////////////////////////////////////////////////////
INLINE size_t MemoryUsage::
get_total_cpp_size() {
  return get_global_ptr()->_total_cpp_size;
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::get_panda_heap_single_size
//       Access: Public, Static
//  Description: Returns the total number of bytes allocated from the
//               heap from code within Panda, for individual objects.
////////////////////////////////////////////////////////////////////
INLINE size_t MemoryUsage::
get_panda_heap_single_size() {
  return AtomicAdjust::get(get_global_ptr()->_total_heap_single_size);
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::get_panda_heap_array_size
//       Access: Public, Static
//  Description: Returns the total number of bytes allocated from the
//               heap from code within Panda, for arrays.
////////////////////////////////////////////////////////////////////
INLINE size_t MemoryUsage::
get_panda_heap_array_size() {
  return AtomicAdjust::get(get_global_ptr()->_total_heap_array_size);
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::get_panda_heap_overhead
//       Access: Public, Static
//  Description: Returns the extra bytes allocated from the system
//               that are not immediately used for holding allocated
//               objects.  This can only be determined if
//               ALTERNATIVE_MALLOC is enabled.
////////////////////////////////////////////////////////////////////
INLINE size_t MemoryUsage::
get_panda_heap_overhead() {
#if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
  MemoryUsage *mu = get_global_ptr();
  return AtomicAdjust::get(mu->_requested_heap_size) - AtomicAdjust::get(mu->_total_heap_single_size) - AtomicAdjust::get(mu->_total_heap_array_size);
#else
  return 0;
#endif
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::get_panda_mmap_size
//       Access: Public, Static
//  Description: Returns the total number of bytes allocated from the
//               virtual memory pool from code within Panda.
////////////////////////////////////////////////////////////////////
INLINE size_t MemoryUsage::
get_panda_mmap_size() {
  return AtomicAdjust::get(get_global_ptr()->_total_mmap_size);
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::get_external_size
//       Access: Public, Static
//  Description: Returns the total number of bytes of allocated memory
//               in the heap that Panda didn't seem to be responsible
//               for.  This includes a few bytes for very low-level
//               objects (like ConfigVariables) that cannot use Panda
//               memory tracking because they are so very low-level.
//
//               This also includes all of the memory that might have
//               been allocated by a high-level interpreter, like
//               Python.
//
//               This number is only available if Panda is able to
//               hook into the actual heap callback.
////////////////////////////////////////////////////////////////////
INLINE size_t MemoryUsage::
get_external_size() {
  MemoryUsage *mu = get_global_ptr();
  if (mu->_count_memory_usage) {
    // We can only possibly know this with memory counting, which
    // tracks every malloc call.

#if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
    // With alternative malloc, none of the Panda allocated memory
    // shows up in total_size, so anything there is external.
    return mu->_total_size;
#else
    // Without alternative malloc, the Panda allocated memory is also
    // included in total_size, so we have to subtract it out.
    return mu->_total_size - mu->_total_heap_single_size - mu->_total_heap_array_size;
#endif
  } else {
    return 0;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::get_total_size
//       Access: Public, Static
//  Description: Returns the total size of allocated memory consumed
//               by the process, as nearly as can be determined.
////////////////////////////////////////////////////////////////////
INLINE size_t MemoryUsage::
get_total_size() {
  MemoryUsage *mu = get_global_ptr();
  if (mu->_count_memory_usage) {
    return mu->_total_size + mu->_requested_heap_size;
  } else {
#if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
    return mu->_requested_heap_size;
#else
    return AtomicAdjust::get(mu->_total_heap_single_size) + AtomicAdjust::get(mu->_total_heap_array_size);
#endif
  }
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::get_num_pointers
//       Access: Public, Static
//  Description: Returns the number of pointers currently active.
////////////////////////////////////////////////////////////////////
INLINE int MemoryUsage::
get_num_pointers() {
  return get_global_ptr()->ns_get_num_pointers();
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::get_pointers
//       Access: Public, Static
//  Description: Fills the indicated MemoryUsagePointers with the set
//               of all pointers currently active.
////////////////////////////////////////////////////////////////////
INLINE void MemoryUsage::
get_pointers(MemoryUsagePointers &result) {
  get_global_ptr()->ns_get_pointers(result);
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::get_pointers_of_type
//       Access: Public, Static
//  Description: Fills the indicated MemoryUsagePointers with the set
//               of all pointers of the indicated type currently
//               active.
////////////////////////////////////////////////////////////////////
INLINE void MemoryUsage::
get_pointers_of_type(MemoryUsagePointers &result, TypeHandle type) {
  get_global_ptr()->ns_get_pointers_of_type(result, type);
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::get_pointers_of_age
//       Access: Public, Static
//  Description: Fills the indicated MemoryUsagePointers with the set
//               of all pointers that were allocated within the range
//               of the indicated number of seconds ago.
////////////////////////////////////////////////////////////////////
INLINE void MemoryUsage::
get_pointers_of_age(MemoryUsagePointers &result, double from, double to) {
  get_global_ptr()->ns_get_pointers_of_age(result, from, to);
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::get_pointers_with_zero_count
//       Access: Public, Static
//  Description: Fills the indicated MemoryUsagePointers with the set
//               of all currently active pointers (that is, pointers
//               allocated since the last call to freeze(), and not
//               yet freed) that have a zero reference count.
//
//               Generally, an undeleted pointer with a zero reference
//               count means its reference count has never been
//               incremented beyond zero (since once it has been
//               incremented, the only way it can return to zero would
//               free the pointer).  This may include objects that are
//               allocated statically or on the stack, which are never
//               intended to be deleted.  Or, it might represent a
//               programmer or compiler error.
//
//               This function has the side-effect of incrementing
//               each of their reference counts by one, thus
//               preventing them from ever being freed--but since they
//               hadn't been freed anyway, probably no additional harm
//               is done.
////////////////////////////////////////////////////////////////////
INLINE void MemoryUsage::
get_pointers_with_zero_count(MemoryUsagePointers &result) {
  get_global_ptr()->ns_get_pointers_with_zero_count(result);
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::freeze
//       Access: Public, Static
//  Description: 'Freezes' all pointers currently stored so that they
//               are no longer reported; only newly allocate pointers
//               from this point on will appear in future information
//               requests.  This makes it easier to differentiate
//               between continuous leaks and one-time memory
//               allocations.
////////////////////////////////////////////////////////////////////
INLINE void MemoryUsage::
freeze() {
  get_global_ptr()->ns_freeze();
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::show_current_types
//       Access: Public, Static
//  Description: Shows the breakdown of types of all of the
//               active pointers.
////////////////////////////////////////////////////////////////////
INLINE void MemoryUsage::
show_current_types() {
  get_global_ptr()->ns_show_current_types();
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::show_trend_types
//       Access: Public, Static
//  Description: Shows the breakdown of types of all of the
//               pointers allocated and freed since the last call to
//               freeze().
////////////////////////////////////////////////////////////////////
INLINE void MemoryUsage::
show_trend_types() {
  get_global_ptr()->ns_show_trend_types();
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::show_current_ages
//       Access: Public, Static
//  Description: Shows the breakdown of ages of all of the
//               active pointers.
////////////////////////////////////////////////////////////////////
INLINE void MemoryUsage::
show_current_ages() {
  get_global_ptr()->ns_show_current_ages();
}

////////////////////////////////////////////////////////////////////
//     Function: MemoryUsage::show_trend_ages
//       Access: Public, Static
//  Description: Shows the breakdown of ages of all of the
//               pointers allocated and freed since the last call to
//               freeze().
////////////////////////////////////////////////////////////////////
INLINE void MemoryUsage::
show_trend_ages() {
  get_global_ptr()->ns_show_trend_ages();
}
